#include <iostream>
#include <unistd.h>
#include <cassert>
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <ctime>
#include <cstdio>
#include <vector>
#include <string>

#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>

//制作随机数种子
#define MakeSeed() srand((unsigned int)time(nullptr) ^ (unsigned int)time(nullptr) & 0x43883983)



//子进程个数
#define SUB_SIZE 5
typedef void (*func_t)();

void DownLoadTask()
{
    std::cout << getpid() << ": 下载任务\n" << std::endl;
    sleep(1);
}

void ReadTask()
{
    std::cout << getpid() << ": 读任务\n" << std::endl;
    sleep(1);

}

void WriteTask()
{
    std::cout << getpid() <<  ": 写任务\n" << std::endl;
    sleep(1);
}

//加载任务表
void LoadTask(std::vector<func_t>* ptable)
{
    assert(ptable);
    ptable->push_back(DownLoadTask);
    ptable->push_back(ReadTask);
    ptable->push_back(WriteTask);

}

struct SubEP
{
    SubEP(const pid_t& subPid, const int& writeFd)
    :subPid_(subPid), writeFd_(writeFd)
    {
        char buffer[1024];
        snprintf(buffer, sizeof buffer, "sub%d[pid: %d - fd[%d]]", num++, subPid_, writeFd_);
        name_ = buffer;
    }
    static int num;
    std::string name_;
    pid_t subPid_;
    int writeFd_;
};

int SubEP::num = 0;


//创建好子进程，并且维护好父子进程通信管道
void CreateSubProcess(std::vector<SubEP>* ps, const std::vector<func_t>& taskMap)
{   
    std::vector<int> deleteFd;
    for(int i = 0; i < SUB_SIZE; ++i)
    {
        int fds[2];
        int n = pipe(fds);
        if(n == -1)
        {
            std::cout << "error: " << errno << " " << strerror(errno) << std::endl;
        }
        pid_t id = fork();
        if(id == 0)
        {
            //子进程
            close(fds[1]); //关闭写端
            while(true)
            {
                //删除多余的写入管道
                for(auto& e : deleteFd)
                {
                    close(e);
                }


                //开始接收信息
                int taskIndex = 0;
                //若父进程没有发送任务，阻塞式等待
                int n = read(fds[0], &taskIndex, sizeof(int));
                if(n == 0)  break;


                //完成任务
                taskMap[taskIndex]();

            }
            close(fds[0]);
            exit(0);
        }
        //父进程
        close(fds[0]); //关闭读端
        deleteFd.push_back(fds[1]);
        SubEP sub(id, fds[1]);
        ps->push_back(sub);
    }
}   

//开始给子进程发送任务
void SendToSubProcess(const SubEP& sub, int taskCode)
{
    std::cout << "父进程正在给" << sub.name_ << "发送任务" << taskCode << std::endl; 
    ssize_t s = write(sub.writeFd_, &taskCode, sizeof(taskCode));
    assert(s == sizeof(int));
    (void)s;
}

//走到这里就是父进程, 控制子进程，负载均衡的向子进程发送命令码
void BlanceControlSubProcess(const std::vector<SubEP>& subs, const std::vector<func_t>& taskMap, int cnt)
{
    int subNum = subs.size();
    int taskNum = taskMap.size();

    bool forever = (cnt == 0 ? true : false);
    while(true)
    {
        //随机选择给哪个子进程发信息
        int subIndex = rand() % subNum;

        //随机选择发送的任务
        int taskIndex = rand() % taskNum;

        
        //开始给子进程发送任务
        SendToSubProcess(subs[subIndex], taskIndex);
        if(!forever)
        {
            cnt--;
            if(cnt == 0) break;
        }
        sleep(1);
    }
    
    //关闭所有父进程对管道的写入
    for(int i = 0; i < subNum; ++i)     
    {
        close(subs[i].writeFd_); 
        //waitpid(subs[i].subPid_, nullptr, 0);
    }

}


//回收子进程
void FreeSub(const std::vector<SubEP>& subs)
{
    int size = subs.size();
    for(int i = 0; i < size; ++i)
    {
        std::cout << "waitpid: " << subs[i].subPid_ << std::endl;
        waitpid(subs[i].subPid_, nullptr, 0);
    }
}
int main()
{
    //制作随机数种子
    MakeSeed();

    std::vector<func_t> taskMap;
    //加载任务表
    LoadTask(&taskMap);
    
    std::vector<SubEP> subs; 
    //创建好子进程，并且维护好父子进程通信管道
    CreateSubProcess(&subs, taskMap);

    //走到这里就是父进程, 控制子进程，负载均衡的向子进程发送命令码
    int cnt = 3; //控制子进程次数，若为-1则一直控制
    BlanceControlSubProcess(subs, taskMap, cnt);

    sleep(1);
    //回收子进程
    FreeSub(subs);
    return 0;
}